﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;



namespace DARE
{
    public class COctreeAABBModel
    {

    #region fields

        private Color m_color;
        private Vector3 m_position;
        private VertexPositionColor[] m_vertices;
        private VertexBuffer m_vertexBuffer;
        private BasicEffect m_basicEffect;
        private Vector3 m_startColor;
        private Vector3 m_endColor;

    #endregion

    #region properties

        /// <summary>
        /// Color of the octree aabb model.
        /// Get the color.
        /// </summary>
        public Color Color
        {
            get { return m_color; }
        }

    #endregion

    #region ctor

        /// <summary>
        /// Create the octree aabb model from a bouding box and his depth for the color.
        /// This is the viewable box of an octree node.
        /// </summary>
        /// <param name="aabb">Bounding box to transform in a visual model.</param>
        /// <param name="depth">Depth of the box to define the color.</param>
        public COctreeAABBModel(BoundingBox aabb, int depth)
        {
            float colorStep = 0.2f;
            m_startColor = Color.Blue.ToVector3();
            m_endColor = Color.Red.ToVector3();

            m_color = new Color(Vector3.Lerp(m_startColor, m_endColor, colorStep * (depth + 1)));
            m_basicEffect = CDare.Instance.XnaBasicEffect;
            SetUpVertices(aabb, depth == -1 ? true : false);
        }

    #endregion

    #region methods
        
        /// <summary>
        /// Create all the vertices of the model.
        /// </summary>
        /// <param name="aabb">Bounding box.</param>
        /// <param name="top">If the box is on top it must have borders, otherwise the borders are visualy for 1/8 the same as the parent.</param>
        private void SetUpVertices(BoundingBox aabb, bool top)
        {
            if (top)
            {
                // allocate space for our vertices
                m_vertices = new VertexPositionColor[24];

                float xMin = aabb.Min.X;
                float xMax = aabb.Max.X;
                float yMin = aabb.Min.Y;
                float yMax = aabb.Max.Y;
                float zMin = aabb.Min.Z;
                float zMax = aabb.Max.Z;
                int count = 0;

                // front
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMin, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMin, zMin), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMax, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMax, zMin), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMin, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMax, zMin), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMin, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMax, zMin), m_color);

                // back
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMin, zMax), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMin, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMax, zMax), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMax, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMin, zMax), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMax, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMin, zMax), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMax, zMax), m_color);

                // link
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMin, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMin, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMin, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMin, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMax, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMax, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMax, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMax, zMax), m_color);
            }
            else
            {
                // allocate space for our vertices
                m_vertices = new VertexPositionColor[30];

                float xMin = aabb.Min.X;
                float xMax = aabb.Max.X;
                float yMin = aabb.Min.Y;
                float yMax = aabb.Max.Y;
                float zMin = aabb.Min.Z;
                float zMax = aabb.Max.Z;
                float xHalf = xMax - (xMax - xMin) / 2.0f;
                float yHalf = yMax - (yMax - yMin) / 2.0f;
                float zHalf = zMax - (zMax - zMin) / 2.0f;
                int count = 0;

                // faces
                // x
                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMin, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMax, zMin), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMin, zMax), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMax, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMin, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMin, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMax, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMax, zMax), m_color);

                // y
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yHalf, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yHalf, zMin), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yHalf, zMax), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yHalf, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yHalf, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yHalf, zMax), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yHalf, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yHalf, zMax), m_color);

                // z
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMin, zHalf), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMin, zHalf), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMax, zHalf), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMax, zHalf), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMin, zHalf), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yMax, zHalf), m_color);

                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMin, zHalf), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yMax, zHalf), m_color);

                // links
                // x axis
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMin, yHalf, zHalf), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xMax, yHalf, zHalf), m_color);

                // y axis
                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMin, zHalf), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yMax, zHalf), m_color);

                // z axis
                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yHalf, zMin), m_color);
                m_vertices[count++] = new VertexPositionColor(new Vector3(xHalf, yHalf, zMax), m_color);
            }

            // set the vertex buffer
            m_vertexBuffer = new VertexBuffer(CDare.Instance.GraphicsDevice, typeof(VertexPositionColor), m_vertices.Length, BufferUsage.WriteOnly);
            m_vertexBuffer.SetData(m_vertices);
        }

        /// <summary>
        /// Draw the model.
        /// </summary>
        public void Draw()
        {
            CDare.Instance.GraphicsDevice.SetVertexBuffer(m_vertexBuffer);

            m_basicEffect.VertexColorEnabled = true;
            m_basicEffect.LightingEnabled = false;

            m_basicEffect.World = Matrix.CreateTranslation(m_position);
            m_basicEffect.View = CDare.Instance.SceneMgr.ActiveScene.ActiveRender3D.CameraMgr.ActiveCamera.View;
            m_basicEffect.Projection = CDare.Instance.SceneMgr.ActiveScene.ActiveRender3D.CameraMgr.ActiveCamera.Projection;

            foreach (EffectPass pass in m_basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                CDare.Instance.GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, m_vertices.Length / 2);
            }
        }

    #endregion

    }
}
